package com.mlethe.library.widget.ripple;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;

import androidx.annotation.NonNull;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 水波纹特效
 *
 * @author Mlethe
 */
public class RippleView extends View {

    private static final int NO_MESSAGE = 10000;

    private Matrix matrix = new Matrix();
    ;

    /**
     * 中心图片资源id
     */
    private int mCenterImageId;

    /**
     * 中心图片
     */
    private Bitmap mCenterImage;

    /**
     * 图片宽度、高度
     */
    private float mImageWidth, mImageHeight;

    /**
     * 中心圆paint
     */
    private Paint mCenterPaint;

    /**
     * 中心圆颜色
     */
    private int mCenterColor;

    /**
     * 中心圆半径
     */
    private float mCenterRadius;

    /**
     * View宽
     */
    private float mWidth;

    /**
     * View高
     */
    private float mHeight;

    /**
     * 画笔对象
     */
    private Paint mPaint;

    /**
     * 开始波纹半径
     */
    private float mStartRadius;

    /**
     * 开始透明度
     */
    private int mStartAlpha = 255;

    /**
     * 最大波纹半径
     */
    private float mMaxRadius;

    /**
     * 波纹的颜色
     */
    private int mRippleColor;

    /**
     * 波纹的宽度
     */
    private float mRippleWidth;

    /**
     * 动画自动播放
     */
    private boolean mRippleAuto;

    /**
     * 波纹是否为填充模式
     */
    private boolean mIsFill;

    /**
     * 一个波纹从创建到消失的持续时间
     */
    private long mRippleDuration;
    /**
     * 波纹的创建速度，每500ms创建一个
     */
    private int mRippleSpeed = 500;
    private float mMaxRadiusRate = 0.85f;
    private boolean mMaxRadiusSet;

    private boolean mIsRunning;

    private List<Circle> mCircleList = new ArrayList<>();

    private Interpolator mInterpolator = new LinearInterpolator();

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            if (msg.what == NO_MESSAGE) {
                if (mIsRunning && mRippleColor != 0) {
                    newCircle();
                    mHandler.removeMessages(NO_MESSAGE);
                    mHandler.sendEmptyMessageDelayed(NO_MESSAGE, mRippleSpeed);
                } else {
                    mHandler.removeMessages(NO_MESSAGE);
                }
            }
        }
    };

    public RippleView(Context context) {
        this(context, null);
    }

    public RippleView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RippleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 获取用户配置属性
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.RippleView);
        mStartRadius = array.getDimension(R.styleable.RippleView_startRadius, 0);
        int alpha = array.getInt(R.styleable.RippleView_startAlpha, mStartAlpha);
        if (alpha >= 0 && alpha <= 255) {
            mStartAlpha = alpha;
        }
        mCenterImageId = array.getResourceId(R.styleable.RippleView_centerImage, 0);
        mImageWidth = array.getDimension(R.styleable.RippleView_imageWidth, 0);
        mImageHeight = array.getDimension(R.styleable.RippleView_imageHeight, 0);
        mCenterColor = array.getColor(R.styleable.RippleView_centerColor, 0);
        mCenterRadius = array.getDimension(R.styleable.RippleView_centerRadius, 0);
        mRippleColor = array.getColor(R.styleable.RippleView_rippleColor, 0);
        mRippleDuration = array.getInt(R.styleable.RippleView_rippleDuration, 2000);
        mRippleSpeed = array.getInt(R.styleable.RippleView_rippleSpeed, mRippleSpeed);
        mIsFill = array.getBoolean(R.styleable.RippleView_rippleIsFill, true);
        mRippleWidth = array.getDimension(R.styleable.RippleView_rippleWidth, dip2px(1));
        mRippleAuto = array.getBoolean(R.styleable.RippleView_rippleAuto, false);
        mMaxRadius = array.getDimension(R.styleable.RippleView_rippleMaxRadius, 0);
        mMaxRadiusRate = array.getFloat(R.styleable.RippleView_rippleMaxRadiusRate, 0.85f);
        if (mMaxRadius != 0) {
            mMaxRadiusSet = true;
        }
        array.recycle();
        init();
    }

    private void init() {
        mCenterPaint = new Paint();
        mCenterPaint.setColor(mCenterColor);
        mCenterPaint.setAntiAlias(true);
        // 设置画笔样式
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(mRippleColor);
        mPaint.setStrokeWidth(mRippleWidth);
        if (mIsFill) {
            mPaint.setStyle(Paint.Style.FILL);
        } else {
            mPaint.setStyle(Paint.Style.STROKE);
        }
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setAntiAlias(true);

        // 设置View的圆为半透明
        setBackgroundColor(Color.TRANSPARENT);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mCenterImage == null) {
            mCenterImage = createBitmap(matrix, mCenterImageId, mImageWidth, mImageHeight);
        }
        if (mRippleAuto) {
            start();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mCenterImage != null) {
            mCenterImage.recycle();
            mCenterImage = null;
        }
    }

    /**
     * 创建绘制的图像
     *
     * @param matrix
     * @param resId
     * @param width
     * @param height
     * @return
     */
    private Bitmap createBitmap(Matrix matrix, int resId, float width, float height) {
        if (resId != 0) {
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId);
            int bitmapWidth = bitmap.getWidth();
            int bitmapHeight = bitmap.getHeight();
            matrix.reset();
            // 获取缩放比例
            float scaleWidth = 1;
            if (width > 0) {
                scaleWidth = width / bitmapWidth;
            }
            float scaleHeight = 1;
            if (height > 0) {
                scaleHeight = height / bitmapHeight;
            }
            if (scaleWidth == 1 && scaleHeight == 1) {
                return bitmap;
            }
            matrix.postScale(scaleWidth, scaleHeight);
            // 根据缩放比例获取新的位图
            Bitmap createdBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, true);
            bitmap.recycle();
            bitmap = null;
            return createdBitmap;
        }
        return null;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        if (!mMaxRadiusSet) {
            mMaxRadius = Math.min(w, h) * mMaxRadiusRate / 2.0f;
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        mWidth = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        mHeight = MeasureSpec.getSize(heightMeasureSpec);

        // MeasureSpec.AT_MOST：在布局中指定了wrap_content；MeasureSpec.EXACTLY：在布局中指定了确切的值，如100dp，match_parent，fill_parent；MeasureSpec.UNSPECIFIED：尽可能的大，很少能用到，如ListView，ScrollView
        if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.EXACTLY) {
            mWidth = dip2px(120);
        } else if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.AT_MOST) {
            mHeight = dip2px(120);
        } else if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
            mWidth = dip2px(120);
            mHeight = dip2px(120);
        }
        // 设置该view的宽高
        setMeasuredDimension((int) mWidth, (int) mHeight);
    }

    @Override
    protected void onWindowVisibilityChanged(int visibility) {
        if (visibility == VISIBLE) {
            int size = mCircleList.size();
            if (size > 0) {
                long timeMillis = System.currentTimeMillis();
                long time = timeMillis - mCircleList.get(mCircleList.size() - 1).mCreateTime;
                for (Circle circle : mCircleList) {
                    circle.mCreateTime += time;
                }
                mHandler.removeMessages(NO_MESSAGE);
                mHandler.sendEmptyMessageDelayed(NO_MESSAGE, mRippleSpeed - time % mRippleSpeed);
            }
        } else {
            mHandler.removeMessages(NO_MESSAGE);
        }
        super.onWindowVisibilityChanged(visibility);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mRippleColor != 0) {
            Iterator<Circle> iterator = mCircleList.iterator();
            while (iterator.hasNext()) {
                Circle circle = iterator.next();
                float radius = circle.getCurrentRadius();
                if (System.currentTimeMillis() - circle.mCreateTime < mRippleDuration) {
                    mPaint.setAlpha(circle.getAlpha());
                    canvas.drawCircle(mWidth / 2, mHeight / 2, radius, mPaint);
                } else {
                    iterator.remove();
                }
            }
        }
        // 绘制中心圆和图片
        drawCenterCircleAndImg(canvas);
        if (mCircleList.size() > 0 && mRippleColor != 0) {
            postInvalidateDelayed(15);
        }
    }

    /**
     * 绘制中心圆和图片
     *
     * @param canvas
     */
    private void drawCenterCircleAndImg(Canvas canvas) {
        if (mCenterColor != 0 && mCenterRadius > 0) {
            // 中间的圆
            canvas.drawCircle(mWidth / 2, mHeight / 2, mCenterRadius, mCenterPaint);
        }
        if (mCenterImage != null && !mCenterImage.isRecycled()) {
            float left = (mWidth - mCenterImage.getWidth()) / 2;
            float top = (mHeight - mCenterImage.getHeight()) / 2;
            canvas.drawBitmap(mCenterImage, left, top, null);
        }
    }

    /**
     * dp转px
     *
     * @param dp
     * @return
     */
    private float dip2px(float dp) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
    }

    /**
     * 创建中心图片bitmap
     *
     * @return
     */
    private void createCenterImage() {
        if (this.mCenterImage != null) {
            this.mCenterImage.recycle();
            this.mCenterImage = null;
        }
        mCenterImage = createBitmap(matrix, mCenterImageId, mImageWidth, mImageHeight);
    }

    /**
     * 设置水波纹开始半径（单位：dp）
     *
     * @param radius
     * @return
     */
    public RippleView setStartRadius(float radius) {
        this.mStartRadius = dip2px(radius);
        return this;
    }

    /**
     * 设置水波纹开始半径（单位：px）
     *
     * @param radius
     * @return
     */
    public RippleView setStartRadius(int radius) {
        this.mStartRadius = radius;
        return this;
    }

    /**
     * 设置水波纹开始透明度
     *
     * @param alpha
     * @return
     */
    public RippleView setStartAlpha(int alpha) {
        this.mStartAlpha = alpha;
        return this;
    }

    /**
     * 设置水波纹圆环宽度（单位：dp）
     *
     * @param width
     * @return
     */
    public RippleView setRippleWidth(float width) {
        width = dip2px(width);
        if (this.mRippleWidth == width) {
            return this;
        }
        this.mRippleWidth = width;
        mPaint.setStrokeWidth(mRippleWidth);
        return this;
    }

    /**
     * 设置水波纹圆环宽度（单位：px）
     *
     * @param width
     * @return
     */
    public RippleView setRippleWidth(int width) {
        if (this.mRippleWidth == width) {
            return this;
        }
        this.mRippleWidth = width;
        mPaint.setStrokeWidth(mRippleWidth);
        return this;
    }

    /**
     * 设置水波纹播放总时长
     *
     * @param duration
     */
    public RippleView setRippleDuration(long duration) {
        this.mRippleDuration = duration;
        return this;
    }

    /**
     * 设置水波纹播放的最大半径
     *
     * @param maxRadius
     * @return
     */
    public RippleView setMaxRadius(float maxRadius) {
        this.mMaxRadius = maxRadius;
        this.mMaxRadiusSet = true;
        return this;
    }

    /**
     * 设置水波纹播放速率
     *
     * @param speed
     * @return
     */
    public RippleView setRippleSpeed(int speed) {
        this.mRippleSpeed = speed;
        return this;
    }

    /**
     * 设置动画插值器
     *
     * @param interpolator
     * @return
     */
    public RippleView setInterpolator(Interpolator interpolator) {
        if (interpolator != null) {
            this.mInterpolator = interpolator;
        }
        return this;
    }

    /**
     * 设置最大半径比例
     *
     * @param maxRadiusRate
     * @return
     */
    public RippleView setMaxRadiusRate(float maxRadiusRate) {
        this.mMaxRadiusRate = maxRadiusRate;
        this.mMaxRadiusSet = false;
        mMaxRadius = Math.min(mWidth, mHeight) * mMaxRadiusRate / 2.0f;
        return this;
    }

    /**
     * 波纹开始的颜色
     *
     * @param color
     * @return
     */
    public RippleView setRippleColor(int color) {
        if (this.mRippleColor == color) {
            return this;
        }
        this.mRippleColor = color;
        mPaint.setColor(color);
        return this;
    }

    /**
     * 波纹是否为填充模式
     *
     * @param isFill
     * @return
     */
    public RippleView setRippleFill(boolean isFill) {
        if (this.mIsFill == isFill) {
            return this;
        }
        this.mIsFill = isFill;
        if (mIsFill) {
            mPaint.setStyle(Paint.Style.FILL);
        } else {
            mPaint.setStyle(Paint.Style.STROKE);
        }
        return this;
    }

    /**
     * 设置中心图片资源
     *
     * @param resId
     * @return
     */
    public RippleView setCenterImageId(int resId) {
        if (this.mCenterImageId == resId) {
            return this;
        }
        this.mCenterImageId = resId;
        createCenterImage();
        if (!mIsRunning) {
            invalidate();
        }
        return this;
    }

    /**
     * 设置中心图片
     *
     * @param bitmap
     * @return
     */
    public RippleView setCenterImage(Bitmap bitmap) {
        if (this.mCenterImage != null) {
            this.mCenterImage.recycle();
            this.mCenterImage = null;
        }
        this.mCenterImage = bitmap;
        if (!mIsRunning) {
            invalidate();
        }
        return this;
    }

    /**
     * 设置中心图片宽度（单位：px）
     *
     * @param width
     * @return
     */
    public RippleView setImageWidth(int width) {
        if (this.mImageWidth == width) {
            return this;
        }
        this.mImageWidth = width;
        createCenterImage();
        if (!mIsRunning) {
            invalidate();
        }
        return this;
    }

    /**
     * 设置中心图片宽度（单位：dp）
     *
     * @param width
     * @return
     */
    public RippleView setImageWidth(float width) {
        width = dip2px(width);
        if (this.mImageWidth == width) {
            return this;
        }
        this.mImageWidth = width;
        createCenterImage();
        if (!mIsRunning) {
            invalidate();
        }
        return this;
    }

    /**
     * 设置中心图片高度（单位：px）
     *
     * @param height
     * @return
     */
    public RippleView setImageHeight(int height) {
        if (this.mImageHeight == height) {
            return this;
        }
        this.mImageHeight = height;
        createCenterImage();
        if (!mIsRunning) {
            invalidate();
        }
        return this;
    }

    /**
     * 设置中心图片高度（单位：dp）
     *
     * @param height
     * @return
     */
    public RippleView setImageHeight(float height) {
        height = dip2px(height);
        if (this.mImageHeight == height) {
            return this;
        }
        this.mImageHeight = height;
        createCenterImage();
        if (!mIsRunning) {
            invalidate();
        }
        return this;
    }

    /**
     * 设置中心圆颜色
     *
     * @param color
     * @return
     */
    public RippleView setCenterColor(int color) {
        if (this.mCenterColor == color) {
            return this;
        }
        this.mCenterColor = color;
        mCenterPaint.setColor(mCenterColor);
        if (!mIsRunning) {
            invalidate();
        }
        return this;
    }

    /**
     * 设置中心圆半径（单位：px）
     *
     * @param radius
     * @return
     */
    public RippleView setCenterRadius(int radius) {
        this.mCenterRadius = radius;
        if (!mIsRunning) {
            invalidate();
        }
        return this;
    }

    /**
     * 设置中心圆半径（单位：dp）
     *
     * @param radius
     * @return
     */
    public RippleView setCenterRadius(float radius) {
        this.mCenterRadius = dip2px(radius);
        if (!mIsRunning) {
            invalidate();
        }
        return this;
    }

    /**
     * 开始
     */
    public void start() {
        if (!mIsRunning) {
            mIsRunning = true;
            newCircle();
            invalidate();
            mHandler.sendEmptyMessageDelayed(NO_MESSAGE, mRippleSpeed);
        }
    }

    /**
     * 缓慢停止
     */
    public void stop() {
        mIsRunning = false;
    }

    /**
     * 立即停止
     */
    public void stopNow() {
        mIsRunning = false;
        mCircleList.clear();
        invalidate();
    }

    private void newCircle() {
        Circle circle = new Circle();
        mCircleList.add(circle);
    }

    private class Circle {
        private long mCreateTime;

        Circle() {
            mCreateTime = System.currentTimeMillis();
        }

        int getAlpha() {
            float percent = (System.currentTimeMillis() - mCreateTime) * 1.0f / mRippleDuration;
            return (int) (mStartAlpha - mInterpolator.getInterpolation(percent) * mStartAlpha);
        }

        float getCurrentRadius() {
            float percent = (System.currentTimeMillis() - mCreateTime) * 1.0f / mRippleDuration;
            return mStartRadius + mInterpolator.getInterpolation(percent) * (mMaxRadius - mStartRadius);
        }
    }
}
